package com.alinesno.cloud.compoment.generate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alinesno.cloud.compoment.generate.generator.AutoGenerator;
import com.alinesno.cloud.compoment.generate.generator.InjectionConfig;
import com.alinesno.cloud.compoment.generate.generator.PropertiesUtil;
import com.alinesno.cloud.compoment.generate.generator.config.DataSourceConfig;
import com.alinesno.cloud.compoment.generate.generator.config.GlobalConfig;
import com.alinesno.cloud.compoment.generate.generator.config.PackageConfig;
import com.alinesno.cloud.compoment.generate.generator.config.StrategyConfig;
import com.alinesno.cloud.compoment.generate.generator.config.rules.DbType;
import com.alinesno.cloud.compoment.generate.generator.config.rules.NamingStrategy;

/**
 * 代码生成工具类
 * @author LuoAnDong
 * @date 2017年9月16日
 */
public abstract class Generator {

	public final Logger logger = LoggerFactory.getLogger(this.getClass());

	public String feiginServer = "" ;  // 服务名称，用于feigin服务调用
	public DbType dbType = DbType.MYSQL ; /* 数据库类型 */
	public String[] tablePrefix = {} ; /* 表前缀 */
	public String[] tableNames; /* 目标表 */
	public List<String> arr = new ArrayList<String>();
	public String parentPackage = ""; /* 父包名 */
	public String moduleName = ""; /* 模块名 */
	public String[] superField  = new String[] {
			"id","fieldProp","addTime","deleteTime","updateTime","hasDelete","hasStatus","deleteManager" , "tenantId" , "applicationId" , 
			"id","field_prop","add_time","delete_time","update_time","has_delete","has_status","delete_manager" , "application_id" , "tenant_id"
			} ;  // 公共字段  

	/**
	 * soa模块前缀
	 */
	public static String SOA_MODULE_PREFIX = "";
	
	// 全局配置
	public GlobalConfig gc = new GlobalConfig();
	
	// 数据源配置
	public DataSourceConfig dsc = new DataSourceConfig();
	
	public String bootPrefix = PropertiesUtil.getString("code.boot.prefix") ; 
	public String outputDir = PropertiesUtil.getString("code.outputdir") ; 
	public String author = PropertiesUtil.getString("code.author") ; 

	public String dbDriverName = null ; 
	public String dbUsername = null ; 
	public String dbPwd = null ; 
	public String dbUrl = null ; 
	public String abcPath = null ; 
	
	public String springApplicationName ; 
	public String serverPort ; 
	public String articleId ; 
	public String groupId ; 
	
	public boolean isOpenFile = true ; 
	
	/**
	 * 初始化参数
	 */
	protected void initParam(String dataSourceType) {
	
		if(StringUtils.isNotBlank(dataSourceType)) {
			dbDriverName = PropertiesUtil.getString("alinesno.database."+dataSourceType+".driver") ; 
			dbUsername = PropertiesUtil.getString("alinesno.database."+dataSourceType+".username") ; 
			dbPwd = PropertiesUtil.getString("alinesno.database."+dataSourceType+".password") ; 
			dbUrl = PropertiesUtil.getString("alinesno.database."+dataSourceType+".url") ; 
		}

		logger.debug("abcPath:{}" , abcPath);
		if(StringUtils.isBlank(abcPath)) {
			abcPath = PropertiesUtil.getString("code.outputdir")  ; 
		}
	
		gc.setOutputDir(outputDir) ; 
		gc.setAuthor(author) ; 
		gc.setOpen(true) ; 
		
		// 数据库源
		dsc.setDriverName(dbDriverName) ; 
		dsc.setUsername(dbUsername) ; 
		dsc.setPassword(dbPwd) ; 
		dsc.setUrl(dbUrl) ; 
	
		springApplicationName = feiginServer ; 
		serverPort = StringUtils.isBlank(serverPort)?"24001":serverPort ; 
		groupId = StringUtils.isBlank(groupId)?(parentPackage + "." + this.buildModelName(moduleName,feiginServer).replace("/", ".")):groupId ; 
		articleId = StringUtils.isBlank(articleId)?feiginServer:articleId ; 
	}
	
	/**
	 * <p>
	 * 生成演示
	 * </p>
	 */
	public void generator(String dataSource) {

		initParam(dataSource);
		initTableName();

		if (tablePrefix == null) {
			logger.warn("table prefix 为空");
		}

		if (SOA_MODULE_PREFIX == null) {
			logger.warn("SOA_MODULE_PREFIX 为空");
		}

		tableNames = new String[arr.size()];
		for (int i = 0; i < arr.size(); i++) {
			tableNames[i] = arr.get(i);
		}

		final AutoGenerator mpg = new AutoGenerator(abcPath);

		gc.setFileOverride(true);
		gc.setActiveRecord(true);
		gc.setEnableCache(false);// XML 二级缓存
		gc.setBaseResultMap(true);// XML ResultMap
		gc.setBaseColumnList(false);// XML columList
		

		mpg.setGlobalConfig(gc);

		dsc.setDbType(dbType);
		mpg.setDataSource(dsc);

		// 策略配置
		final StrategyConfig strategy = new StrategyConfig();
		strategy.setTablePrefix(tablePrefix);// 此处可以修改为您的表前缀
		
		// 持久层
		strategy.setSuperRepositoryClass("com.alinesno.cloud.common.core.orm.repository.IBaseJpaRepository");
		strategy.setIdKeyType("String");
		
		// 服务
		strategy.setSuperServiceClass("com.alinesno.cloud.common.core.services.IBaseService");
		strategy.setSuperServiceImplClass("com.alinesno.cloud.common.core.services.impl.IBaseServiceImpl");
		strategy.setSuperEntityClass("com.alinesno.cloud.common.core.orm.entity.BaseEntity");
		
		// Rest接口
		strategy.setSuperRestControllerClass("com.alinesno.cloud.common.core.rest.BaseRestController") ; 
		
		// boot 接口
		strategy.setBootPrefix(bootPrefix);
		
		// Feigin接口
		strategy.setSuperFeiginDtoClass("com.alinesno.cloud.common.facade.feign.BaseDto") ; 
		strategy.setFeiginServer(feiginServer);
			
		//前端
		strategy.setControllerMappingHyphenStyle(true) ;
		strategy.setSuperControllerClass("com.alinesno.training.common.base.BaseController");
		
		strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略
		strategy.setInclude(tableNames); // 需要生成的表
		
		strategy.setSuperEntityColumns(superField) ; 
		
		mpg.setStrategy(strategy);

		// 包配置
		final PackageConfig pc = new PackageConfig();
		pc.setParent(parentPackage);
		pc.setModuleName(buildModelName(moduleName , feiginServer));
		pc.setController("controller");
		
		// yml and pom.xml
		pc.setSpringApplicationName(springApplicationName); 
		pc.setServerPort(serverPort);
		pc.setArticleId(articleId);
		pc.setGroupId(groupId);
		
		pc.setDatabaseDriverClass(dsc.getDriverName());
		pc.setDatabaseUrl(dsc.getUrl());
		pc.setDatabaseUsername(dsc.getUsername());
		pc.setDatabasePassword(dsc.getPassword()); 
		pc.setAbcPath(abcPath); 
		
		gc.setModuleName(pc.getModuleName());
		mpg.setPackageInfo(pc);

		// 注入自定义配置，可以在 VM 中使用 cfg.abc 设置的值
		final InjectionConfig cfg = new InjectionConfig() {
			@Override
			public void initMap() {
				final Map<String, Object> map = new HashMap<String, Object>();
				map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
				this.setMap(map);
			}
		};
		mpg.setCfg(cfg);
		mpg.execute(pc);
		logger.debug("代码生成成功.");

		// 打印注入设置
		System.err.println(mpg.getCfg().getMap().get("abc"));
	}

	/**
	 * 创建模块名称
	 * @param moduleName
	 * @return
	 */
	protected String buildModelName(String moduleName , String feiginServer) {
		if(StringUtils.isBlank(moduleName)) {
			String p = feiginServer.replace("alinesno-cloud-", "").replace("-", "/") ; 
			moduleName = p ; 
		}
		logger.debug("moduleName:{}" , moduleName) ; 
		return moduleName ; 
	}

	/**
	 * 数组转换成集合
	 * @param tableNames
	 * @return
	 */
	public List<String> toArray(String[] tableNames) {
		List<String> arr = new ArrayList<String>() ; 
		for(String s :tableNames) {
			arr.add(s) ;
		}
		return arr ;
	}

	/**
	 * 
	 */
	public abstract void initTableName();

}
